package com.bilibili.service.impl;

import cn.hutool.core.date.DateTime;
import com.bilibili.dto.ResetPwdVo;
import com.bilibili.entity.MyCoin;
import com.bilibili.entity.User;
import com.bilibili.exception.BusinessException;
import com.bilibili.manage.SmsService;
import com.bilibili.mapper.PersonalMapper;
import com.bilibili.mapper.UserMapper;
import com.bilibili.service.UserService;
import com.bilibili.utils.RandomUtils;
import com.bilibili.utils.RedisOperations;
import com.bilibili.vo.UserLoginVo;
import com.bilibili.vo.UserRegistVo;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;

import java.sql.Timestamp;
import java.time.*;
import java.util.Date;
import java.util.Objects;

import static com.bilibili.constant.BusinessConstant.*;
import static com.bilibili.constant.RegexConstant.PHONE_REGEX;
import static com.bilibili.constant.RegexConstant.STRONG_PWD_REGEX;


@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private PersonalMapper personalMapper;
    @Autowired
    private SmsService smsService;
    @Autowired
    private RedisOperations redisOperations;

    @Override
    public User getUserByUserName(String userName) {
        User user = userMapper.getUserByUserName(userName);
        if (Objects.isNull(user)) {
            throw new BusinessException(HttpStatus.NOT_FOUND, "昵称不存在");
        }
        return user;
    }

    @Override
    public boolean isUserNameExists(String userName) {
        return !Objects.isNull(getUserByUserName(userName));
    }

    @Override
    public boolean modifyUserImg(Integer id, String image) {
        if (StringUtils.isBlank(image)) {
            throw new BusinessException(HttpStatus.BAD_REQUEST, "用户头像不能为空");
        }
        if (Objects.isNull(id)) {
            throw new BusinessException(HttpStatus.NOT_FOUND, "用户id不能为空");
        }

        return userMapper.modifyUserImage(id, image);
    }

    @Override
    public boolean isPhoneExists(String phone) {
        boolean exists = userMapper.getUserByPhone(phone);
        if (!exists) {
            throw new BusinessException(HttpStatus.NOT_FOUND, "手机号不存在");
        }
        return true;
    }

    @Override
    public boolean sendValidateCode(String phone) {
        //手机号非空
        if (StringUtils.isBlank(phone)) {
            throw new BusinessException(HttpStatus.BAD_REQUEST, "手机号不能为空");
        }
        //手机号是否合法
        if (!phone.matches(PHONE_REGEX)) {
            throw new BusinessException(HttpStatus.BAD_REQUEST, "手机号格式不合法");
        }
        //生成验证码
        String code = RandomUtils.generateValidateCode(VALIDATE_CODE_LENGTH);
        boolean smsSuccess = smsService.sendValidateCode(phone, code);
        if (!smsSuccess) {
            throw new BusinessException(HttpStatus.INTERNAL_SERVER_ERROR, "短信发送失败！");
        } else {
            String key = REDIS_VALIDATE_CODE_PREFIX + phone;
            redisOperations.set(key, code);
            redisOperations.expire(key, VALIDATE_CODE_EXPIRE_SECONDS);
        }
        return true;
    }

    @Override
    public User regist(UserRegistVo userRegistVo) {
        String phone = userRegistVo.getPhone();
        String userName = userRegistVo.getUserName();
        String userPwd = userRegistVo.getUserPwd();
        String validateCode = userRegistVo.getValidateCode();
        //用户名非空
        if (StringUtils.isBlank(userName)) {
            throw new BusinessException(HttpStatus.BAD_REQUEST, "用户名不能为空");
        }
        //用户名重复
        if (!Objects.isNull(userMapper.getUserByUserName(userName))) {
            throw new BusinessException(HttpStatus.BAD_REQUEST, "用户名已存在");
        }
        //密码不能为空
        if (StringUtils.isBlank(userPwd)) {
            throw new BusinessException(HttpStatus.BAD_REQUEST, "密码不能为空");
        }
        //密码必须是强类型
        if (!userPwd.matches(STRONG_PWD_REGEX)) {
            throw new BusinessException(HttpStatus.BAD_REQUEST, "密码必须是强密码类型");
        }
        //手机号非空
        if (StringUtils.isBlank(phone)) {
            throw new BusinessException(HttpStatus.BAD_REQUEST, "手机号不能为空");
        }
        //手机号格式
        if (!phone.matches(PHONE_REGEX)) {
            throw new BusinessException(HttpStatus.BAD_REQUEST, "手机号格式不合法");
        }
        //手机号重复性
        if (userMapper.getUserByPhone(phone)) {
            throw new BusinessException(HttpStatus.BAD_REQUEST, "手机号已存在");
        }
        //验证码是否为空
        if (StringUtils.isBlank(validateCode)) {
            throw new BusinessException(HttpStatus.BAD_REQUEST, "验证码不能为空");
        }
        //验证码是否和实际发送到手机的一致
        //判断验证码是否正确
        isValidateCodeCorrect(phone, validateCode);
        //(2-2)用户输入的和Redis中的相等-正确情况，可以继续做后面的逻辑
        User user = new User();
        user.setName(userName);
        user.setPwd(DigestUtils.md5Hex(userPwd));
        user.setPhone(phone);
        user.setImage(DEFAULT_USER_IMAGE);
        user.setMemberId(DEFAULT_USER_MEMBER_ID);
        user.setCoin(DEFAULT_USER_COIN_COUNT);
        boolean success = userMapper.addUser(user);
        if (success) {
            user.setPwd(null);
            return user;
        } else {
            throw new BusinessException(HttpStatus.BAD_REQUEST, "注册用户失败");
        }
    }

    @Override
    public boolean resetPwd(ResetPwdVo resetPwdVo) {
        String phone = resetPwdVo.getPhone();
        String confirmPwd = resetPwdVo.getUserPwdConfirm();
        String userPwd = resetPwdVo.getUserPwd();
        String validateCode = resetPwdVo.getValidateCode();
        //手机号非空
        if (StringUtils.isBlank(phone)) {
            throw new BusinessException(HttpStatus.BAD_REQUEST, "手机号不能为空");
        }
        //手机号格式
        if (!phone.matches(PHONE_REGEX)) {
            throw new BusinessException(HttpStatus.BAD_REQUEST, "手机号格式不合法");
        }
        //密码不能为空
        if (StringUtils.isBlank(userPwd)) {
            throw new BusinessException(HttpStatus.BAD_REQUEST, "密码不能为空");
        }
        //密码必须是强类型
        if (!userPwd.matches(STRONG_PWD_REGEX)) {
            throw new BusinessException(HttpStatus.BAD_REQUEST, "密码必须是强密码类型");
        }
        //密码一致性判断
        if (!StringUtils.equals(confirmPwd,userPwd)) {
            throw new BusinessException(HttpStatus.BAD_REQUEST, "密码不一致");
        }
        //验证码非空
        if (StringUtils.isBlank(validateCode)) {
            throw new BusinessException(HttpStatus.BAD_REQUEST, "验证码不能为空");
        }
        //验证码是否和实际发送到手机的一致
        //判断验证码是否正确
        isValidateCodeCorrect(phone, validateCode);
        //重置密码
        boolean success = userMapper.updatePwdByPhoneOrEmail(phone,DigestUtils.md5Hex(userPwd));
        if(!success){
            throw new BusinessException(HttpStatus.BAD_REQUEST,"重置密码失败");
        }
        return true;
    }

    @Override
    public User login(UserLoginVo userLoginVo) {
        //1.解析数据
        String phoneOrEmail = userLoginVo.getPhoneOrEmail();
        String userPwd = userLoginVo.getUserPwd();
        String phone = userLoginVo.getPhone();
        String validateCode = userLoginVo.getValidateCode();
        boolean loginByPwd = userLoginVo.isLoginByPwd();
        boolean rememberPwd = userLoginVo.isRememberPwd();
        //2.参数校验
        User user = null;
        //密码登录
        if (loginByPwd) {
            //手机号或邮箱进行验证
            if (StringUtils.isBlank(phoneOrEmail)) {
                throw new BusinessException(HttpStatus.BAD_REQUEST, "手机号或邮箱不能为空");
            }
            if (StringUtils.isBlank(userPwd)) {
                throw new BusinessException(HttpStatus.BAD_REQUEST, "用户名密码不能为空");
            }
            user = userMapper.getUserByPhoneOrEmail(phoneOrEmail);
            if (Objects.isNull(user)) {
                throw new BusinessException(HttpStatus.NOT_FOUND, "用户不存在");
            }
            if (!StringUtils.equals(DigestUtils.md5Hex(userPwd), user.getPwd())) {
                throw new BusinessException(HttpStatus.BAD_REQUEST, "密码错误");
            }
        }
        //手机号和验证码登录
        else {
            //手机号和验证码进行验证
            if (StringUtils.isBlank(phone)) {
                throw new BusinessException(HttpStatus.BAD_REQUEST, "手机号不能为空");
            }
            if (StringUtils.isBlank(validateCode)) {
                throw new BusinessException(HttpStatus.BAD_REQUEST, "验证码不能为空");
            }
            if (!userMapper.getUserByPhone(phone)) {
                throw new BusinessException(HttpStatus.BAD_REQUEST, "手机号不存在");
            }
            //判断验证码是否正确
            isValidateCodeCorrect(phone, validateCode);
            user = userMapper.getUserByPhoneOrEmail(phone);
        }
        if (Objects.isNull(user)) {
            throw new BusinessException(HttpStatus.BAD_REQUEST, "用户不存在");
        }
        //记录登录时间，当天第一次登录硬币加2
        Date lastLoginDate = new Date();
        Timestamp timestamp = user.getLoginTime();
        //判断上一次登录时间是否为空,为空则直接加硬币
        if (Objects.isNull(timestamp)) {
            //加硬币
            userMapper.updateCoin(user.getId());
            //添加硬币登录奖励记录
            MyCoin myCoin = new MyCoin();
            myCoin.setUserId(user.getId());
            Timestamp lastLoginDateTimestamp = new Timestamp(lastLoginDate.getTime());
            myCoin.setDateTime(lastLoginDateTimestamp);
            myCoin.setChanges("+2");
            myCoin.setReasons("登录奖励");
            userMapper.addCoinRecord(myCoin);
            personalMapper.addExp(user.getId(),DEFAULT_EXP);
        } else {
            lastLoginDate.setTime(user.getLoginTime().getTime());
            LocalDate currentDate = LocalDate.now();
            LocalDateTime loginTime = lastLoginDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
            LocalDate lastLoginLocalDate = loginTime.toLocalDate();
            //对当前时间进行判断
            if (!currentDate.isEqual(lastLoginLocalDate)) {
                //加硬币
                userMapper.updateCoin(user.getId());
                //添加硬币登录奖励记录
                MyCoin myCoin = new MyCoin();
                myCoin.setUserId(user.getId());
                ZoneId zoneId = ZoneId.systemDefault();
                ZonedDateTime zdt = currentDate.atStartOfDay(zoneId);
                Date currentDates = Date.from(zdt.toInstant());
                Timestamp currentLoginDateTimestamp = new Timestamp(currentDates.getTime());
                myCoin.setDateTime(currentLoginDateTimestamp);
                myCoin.setChanges("+2");
                myCoin.setReasons("登录奖励");
                userMapper.addCoinRecord(myCoin);
                personalMapper.addExp(user.getId(),DEFAULT_EXP);

            }
        }
        //修改登陆时间
        userMapper.updateLoginTime(user.getId());
        //获取最新user
        User loginUser = userMapper.getUserByPhoneOrEmail(user.getPhone());
        loginUser.setPwd(null);
        return user;
    }

    @Override
    public boolean addCoinRecord(MyCoin myCoin) {
        return userMapper.addCoinRecord(myCoin);
    }

    @Override
    public boolean isAchieveLoginAward(Integer userId) {

        if (Objects.isNull(userId)) {
            throw new BusinessException(HttpStatus.NOT_FOUND, "用户id不存在");
        }
       return userMapper.isExistTodayLogin(userId);

    }


    /**
     * 判断该手机号验证码是否正确
     *
     * @param phone
     * @return
     */
    public boolean isValidateCodeCorrect(String phone, String validateCode) {
        //验证码是否和实际发送到手机的一致
        //从Redis中获取当前手机号对应的验证码的信息
        String correctValidateCode = redisOperations.get(REDIS_VALIDATE_CODE_PREFIX + phone);
        //(1)从Redis中没有获取到当前手机号对应的验证码信息-验证码可能失效了（或者压根没法）
        if (StringUtils.isBlank(correctValidateCode)) {
            throw new BusinessException(HttpStatus.BAD_REQUEST, "验证码可能已经失效了，请重新发送~");
        }
        //(2)从Redis中获取到手机号对应的验证码信息
        else {
            //(2-1)用户输入的和Redis中的不相等-验证码输入错误的情况
            if (!StringUtils.equals(correctValidateCode, validateCode)) {
                throw new BusinessException(HttpStatus.BAD_REQUEST, "验证码错误~");
            }
        }
        return true;
    }
}
